﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Urb.Weather.Core.Manager;

namespace Urb.Weather.Manager
{
    internal class ConditionHistory<U, Cond> : SortedDictionary<DateTimeOffset, Cond>
        where Cond : Conditions<U>, new()
    {
        private Func<decimal, U, U, decimal> unitConverter;
        private string sourceName;

        private Cond mostRecent;
        private Cond min;
        private Cond max;

        public ConditionHistory(Func<decimal, U, U, decimal> unitConverter, string sourceName)
        {
            this.unitConverter = unitConverter;
            this.sourceName = sourceName;
        }

        public Cond MostRecent { get { return mostRecent; } }
        public Cond Min { get { return min; } }
        public Cond Max { get { return max; } }

        public Cond GetOrCreate(DateTimeOffset measurementTime)
        {
            if (!this.ContainsKey(measurementTime))
            {
                var cond = new Cond();
                cond.SourceName = this.sourceName;
                cond.MeasurementTime = measurementTime;
                this[measurementTime] = cond;

                if ((mostRecent == null) || (mostRecent.MeasurementTime < measurementTime))
                {
                    mostRecent = cond;
                }
            }

            return this[measurementTime];
        }

        internal ConditionHistoryUpdateResult Update(DateTimeOffset measurementTime, decimal value, U unit)
        {
            var mostRecentChanged = mostRecent == null || mostRecent.MeasurementTime < measurementTime;
            var extremesChanged = false;

            var conditions = GetOrCreate(measurementTime);

            var historyChanged = mostRecentChanged || !conditions.Value.Equals(value) || !conditions.Unit.Equals(unit);

            if (historyChanged)
            {
                conditions.Value = value;
                conditions.Unit = unit;

                mostRecentChanged |= conditions == mostRecent;

                if (min == null)
                {
                    min = new Cond()
                    {
                        MeasurementTime = measurementTime,
                        Value = value,
                        Unit = unit
                    };

                    extremesChanged = true;
                }
                else if (value.CompareTo(unitConverter(min.Value, min.Unit, unit)) <= 0)
                {
                    min.MeasurementTime = measurementTime;
                    min.Value = value;
                    min.Unit = unit;

                    extremesChanged = true;
                }

                if (max == null)
                {
                    max = new Cond()
                    {
                        MeasurementTime = measurementTime,
                        Value = value,
                        Unit = unit
                    };

                    extremesChanged = true;
                }
                else if (value.CompareTo(unitConverter(max.Value, max.Unit, unit)) >= 0)
                {
                    max.MeasurementTime = measurementTime;
                    max.Value = value;
                    max.Unit = unit;

                    extremesChanged = true;
                }

                if (extremesChanged && min.Value.CompareTo(unitConverter(max.Value, max.Unit, min.Unit)) == 0)
                {
                    extremesChanged = false;
                }
            }

            return new ConditionHistoryUpdateResult()
            {
                HistoryChanged = historyChanged,
                MostRecentChanged = mostRecentChanged,
                ExtremesChanged = extremesChanged,
            };
        }
    }

    internal class ConditionHistoryUpdateResult
    {
        public bool HistoryChanged { get; set; }
        public bool MostRecentChanged { get; set; }
        public bool ExtremesChanged { get; set; }
    }
}
